﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GeoUtils
{
    public class LatLong
    {
        private double longitude;
        private double latitude;

        public LatLong(double latitude, double longitude)
        {
            this.longitude = longitude;
            this.latitude = latitude;
        }


        public double Longitude
        {
            get { return longitude; }
            set { longitude = value; }
        }

        public double Latitude
        {
            get { return latitude; }
            set { latitude = value; }
        }

        /// <summary>
        /// Average radius of earth, in terms of meters.
        /// </summary>
        public const double Radius = 6371.004 * 1000;
        public const double Circumference = 2 * Math.PI * Radius;

        /// <summary>
        /// Calculate distance between 2 point.
        /// Formula:
        ///     Δφ = ln(tan(lat2/2+π/4)/tan(lat1/2+π/4)) 
        ///     if E:W line
        ///         q = cos(lat1) (length of a circle of latitude)
        ///     otherwise
        ///         q = Δlat/Δφ
        ///     d = √[Δlat² + q².Δlon²].R 
        ///     θ = atan2(Δlon, Δφ) 
        ///     where ln is natural log, Δlon is taking shortest route ( less than 180º), and R is the earth’s radius 
        /// </summary>
        /// <param name="source">Source point.</param>
        /// <param name="target">Target point.</param>
        /// <returns>Distance in meters.</returns>
        public static double Distance(LatLong source, LatLong target)
        {
            // 
            double longitude1 = source.Longitude / 180.0 * Math.PI;
            double latitude1 = source.Latitude / 180.0 * Math.PI;
            double longitude2 = target.Longitude / 180.0 * Math.PI;
            double latitude2 = target.Latitude / 180.0 * Math.PI;

            // 
            double p = Math.Log(Math.Tan(latitude2 / 2 + Math.PI / 4) / Math.Tan(latitude1 / 2 + Math.PI / 4));
            double q = 0.0;
            if (latitude2 == latitude1)
                q = Math.Cos(latitude1);
            else
                q = (latitude2 - latitude1) / p;
            double d = Math.Sqrt((latitude2 - latitude1) * (latitude2 - latitude1) + q * q * (longitude2 - longitude1) * (longitude2 - longitude1)) * Radius;
            return d;
        }

        public double Distance(LatLong latlong)
        {
            return Distance(this, latlong);
        }
    }
}
